/*
 Copyright (C) 2008  Maurizio Monticelli

 This program is free software; you can redistribute it and/or modify it under the terms of the 
 GNU General Public License as published by the Free Software Foundation; either version 2 of the 
 License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
 even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 
 Public License for more details.

 You should have received a copy of the GNU General Public License along with this program; if not, write 
 to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA 
 */

package ch.justdoit.andriodrpncalc.model;

import java.text.ParseException;
import java.util.Stack;

public class CalcNumber {

	public CalcNumber(Double value, Model _model) {
		doubleNumber = value;
		model = _model;
		type = TYPE.NUMBER;
		empty = false;
		tokenList = new Stack<String>();
		changed();
	}

	public CalcNumber(Model _model) {
		model = _model;
	}
	/*
	 * Internal Variables
	 * 
	 */
	
	public enum TYPE {
		NONE,
		NUMBER,
		EXPRESSION, FRACTION
	}

	protected Double doubleNumber;
	protected String exxpressionString = "";
	// private Long longNumber;

	protected Long numerator = 0l;
	protected Long denominator = 1l;
	protected Model model;

	protected boolean empty = true;
	protected TYPE type = TYPE.NONE;
	protected java.util.Stack<String> tokenList;

	/*
	 * Public Methods
	 */

	private IOnChangedListener onChangedListener = null; 
	
	private void changed(){
		
		if (onChangedListener != null) {
			onChangedListener.changed();
		}
	}
	private boolean toBase = false;

	public boolean isToBase() {
		return toBase;
	}

	public void setToBase(boolean toBase) {
		this.toBase = toBase;
		changed();
	}

	

	public void parse() {
		if (type == TYPE.FRACTION) {
			//parseFaction();
		}
		try {
			parseNumber(getExpressionString());
		} catch (Exception e) {
			empty = false;
			type = TYPE.EXPRESSION;
		}
	}
	
	public void parseNumber(String input) throws ParseException {
		// TODO: Implement

		if (true) {
			doubleNumber = Double.parseDouble(input);
			empty = false;
			type = TYPE.NUMBER;
		}
		changed();
	}

	public void parse(String _numerator, String _denominator) throws ParseException {
		numerator = Long.parseLong(_numerator);
		denominator = Long.parseLong(_denominator);
		changed();
	}

	public void parse(long _numerator, long _denominator) {
		numerator = _numerator;
		denominator = _denominator;
		changed();
	}

	public long getNumerator() {
		return numerator.longValue();
	}

	public void setNumerator(long value) {
		numerator = value;
		changed();
	}

	public void setNumerator(String value) {
		numerator = Long.parseLong(value);
		changed();
	}

	public long getDenominator() {
		return denominator.longValue();
	}

	public void setDenominator(long value) {
		denominator = value;
		changed();
	}

	public void setDenominator(String value) {
		denominator = Long.parseLong(value);
		changed();
	}

	public String toString() {
		String result = "";
		if (!empty) {
			if (type == TYPE.NUMBER) {
				if (isToBase()) {
					if (model.mSettings.getDisplayBase() == Settings.BASE.DEC) {
						result = Integer.toString(doubleNumber.intValue());
						result = "# " + result + "d";
					} else if (model.mSettings.getDisplayBase() == Settings.BASE.BIN) {
						result = Integer.toBinaryString(doubleNumber.intValue());
						result = "# " + result + "b";
					} else if (model.mSettings.getDisplayBase() == Settings.BASE.HEX) {
						result = Integer.toHexString(doubleNumber.intValue());
						result = "# " + result + "h";
					} else if (model.mSettings.getDisplayBase() == Settings.BASE.OCT) {
						result = Integer.toOctalString(doubleNumber.intValue());
						result = "# " + result + "o";
					}
				} else {
					String doubleString = doubleNumber.toString();
					if (model.mSettings.getDigitsAfterPoint() != 0) {
						String v = "";
						String h = "";

						int p = doubleString.indexOf(".");

						v = doubleString.substring(0, p);
						h = doubleString
								.substring(p + 1, doubleString.length());
						if (h.length() < model.mSettings.getDigitsAfterPoint()) {
							for (int i = h.length(); i < model.mSettings
									.getDigitsAfterPoint(); i++) {
								h += "0";
							}
						} else {
							// abschneiden
							h = h.substring(0, model.mSettings
									.getDigitsAfterPoint());
						}

						doubleString = v + "." + h;
					} else {
						if (doubleString.endsWith(".0")) {
							doubleString = doubleString.replace(".0", "");
						}
					}
					result = doubleString;
				}
			} else {
				result = "'" + getExpressionString() + "'";
			}
		}

		return result;
	}

	public double getDouble() {
		return doubleNumber.doubleValue();
	}

	public void setDouble(double value) {
		doubleNumber = value;
		empty = false;
		changed();
	}

	public String getExpressionString() {
		String expressionString = "";
		for (int i = 0; i < tokenList.size(); i++) {
			expressionString += tokenList.get(i);
		}
		return expressionString;
	}


	public boolean isExpression() {
		boolean result = false;
		if (type == TYPE.EXPRESSION)
			result = true;
		return result;
	}

	public boolean isEmpty() {
		boolean result = empty;
		
		if (!tokenList.isEmpty()){
			empty = false;
		} 
		return empty;
	}

	public boolean isNumber() {
		boolean result = false;
		if (type == TYPE.NUMBER)
			result = true;
		return result;
	}
	
	public CalcNumber clone() {
		CalcNumber result = new CalcNumber(model);
		
		result.empty = empty;
		result.denominator = denominator;
		result.doubleNumber = doubleNumber;
		result.type = type;
		//result.expressionString = expressionString;
		result.numerator = numerator;
		result.toBase = toBase;
		result.tokenList = tokenList;
		
		return result;
	}
	
	public void copy(CalcNumber number) {
		empty = number.empty;
		denominator = number.denominator;
		doubleNumber = number.doubleNumber;
		type = number.type;
		//expressionString = number.expressionString;
		numerator = number.numerator;
		toBase = number.toBase;
		tokenList = number.tokenList;
		changed();
		
	}


	public void setOnChangedListener(IOnChangedListener onChangedListener) {
		this.onChangedListener = onChangedListener;
	}

	public void reset() {
		//expressionString = "";
		empty = true;
		type = TYPE.NONE;
		changed();
		
	}
	
	public void setToken(Stack<String> _tokenList) {
		tokenList = _tokenList;
		empty = false;
		changed();
	}
	
	public Stack<String> getTokens() {
		return tokenList;
	}
	
	public void append(String token) {
		tokenList.add(token);
		changed();
	}
	
	public void prepend(String token) {
		tokenList.add(0, token);
		changed();
	}
	

}
